#include "mqtt_client.h"

#include <ctime>
#include <iomanip>
#include <random>
#include <sstream>
#include <thread>

MqttBase::MqttBase(const std::string& broker_addr,
                   const std::string& client_name, const std::string& topic,
                   int qos)
    : client_(broker_addr, client_name), topic_(topic), qos_(qos) {}

MqttBase::~MqttBase() {
  if (client_.is_connected()) {
    std::cout << "正在断开MQTT连接..." << std::endl;
    // 非阻塞断开
    client_.disconnect()->wait_for(std::chrono::seconds(3));
    std::cout << "MQTT连接已断开" << std::endl;
  }
}

void PubCallback::delivery_complete(mqtt::delivery_token_ptr token) {
  std::cout << "收到发布确认：" << std::endl;
}
MqttPublisher::MqttPublisher(const std::string& broker_addr,
                             const std::string& client_name,
                             const std::string& topic, int qos)
    : MqttBase(broker_addr, client_name, topic, qos) {
  con_opts_.set_clean_session(true);
  con_opts_.set_keep_alive_interval(20);
  client_.set_callback(call_back_);
  // 建立连接
  std::cout << "publisher开始向Broker建立连接....." << std::endl;
  client_.connect(con_opts_)
      ->wait();  //  connect返回一个指向tokenshared_ptr指针，等待建立连接成功
  if (client_.is_connected()) {
    std::cout << "连接建立成功" << std::endl;
  } else {
    std::cout << "连接建立失败" << std::endl;
  }
  srand(time(NULL));
}

std::string MqttPublisher::GenerateMessage() {
  int temp = rand() % 40 + 1;            //  温度
  std::time_t now = std::time(nullptr);  // 获取现在时间
  std::tm* local_time = std::localtime(&now);

  // 格式化为字符串
  std::stringstream time_ss;
  time_ss << std::put_time(local_time, "%Y-%m-%d %H:%M:%S");
  std::string time_str = time_ss.str();
  std::stringstream ss;
  ss << "温度:" << std::fixed << std::setprecision(1) << temp
     << " 时间:" << time_str << " 客户端id:" << client_.get_client_id();
  return ss.str();
}

void MqttPublisher::Publish() {
  if (!client_.is_connected()) {
    std::cout << "连接已经断开" << std::endl;
    exit(1);
  }
  //  生成模拟数据
  std::string msg = GenerateMessage();
  // 将消息进行封装
  auto message = mqtt::make_message(topic_, msg);
  message->set_qos(qos_);            // 设置保证等级
  client_.publish(message)->wait();  // 发布消息并等待发布成功

  std::cout << "消息发布成功" << std::endl;
}

void MqttPublisher::Run() {
  std::cout << "=== 发布客户端（数采仪） ===" << std::endl;
  std::cout << "Broker: " << client_.get_server_uri() << std::endl;
  std::cout << "Client ID: " << client_.get_client_id() << std::endl;
  std::cout << "Topic: " << topic_ << std::endl;
  std::cout << "===============================" << std::endl;
  int message_count = 0;
  while (true) {
    Publish();
    std::this_thread::sleep_for(std::chrono::seconds(2));
  }
}

MqttSubscriber::MqttSubscriber(const std::string& broker_addr,
                               const std::string& client_name,
                               const std::string& topic, int qos)
    : MqttBase(broker_addr, client_name, topic, qos) {
  con_opts_.set_clean_session(true);
  con_opts_.set_keep_alive_interval(20);

  // 设置回调（用于接收消息和处理连接事件）
  client_.set_callback(call_back_);

  // 建立连接
  std::cout << "开始向Broker建立连接....." << std::endl;
  client_.connect(con_opts_)->wait();
  if (client_.is_connected()) {
    std::cout << "连接建立成功" << std::endl;
    // 连接成功后立即订阅主题（使用订阅属性）
    auto sub_opts = mqtt::subscribe_options();
    // 连接成功后立即订阅主题
    client_.subscribe(topic_, qos_, sub_opts)->wait();
    std::cout << "已订阅主题: " << topic_ << " (QoS: " << qos_ << ")"
              << std::endl;
  } else {
    std::cout << "连接建立失败" << std::endl;
    exit(1);
  }
}

void MqttSubscriber::Run() {
  std::cout << "=== 订阅客户端 ===" << std::endl;
  std::cout << "Broker: " << client_.get_server_uri() << std::endl;
  std::cout << "Client ID: " << client_.get_client_id() << std::endl;
  std::cout << "订阅主题: " << topic_ << std::endl;

  // 保持主线程运行，持续接收消息
  while (true) {
    std::this_thread::sleep_for(std::chrono::seconds(1));
  }
}

void SubCallBack::message_arrived(mqtt::const_message_ptr msg) {
  std::cout << "主题: " << msg->get_topic() << std::endl;
  std::cout << "内容: " << msg->to_string() << std::endl;
  std::cout << "QoS: " << msg->get_qos() << std::endl;
}

void SubCallBack::connection_lost(const std::string& cause) {
  std::cout << "\n连接断开！原因: " << (cause.empty() ? "未知" : cause)
            << std::endl;
  std::cout << "尝试重新连接..." << std::endl;
}
